from functools import wraps

from django.http import QueryDict

from weiwenhai_Oj.exceptions.data_exception import ValidationException, DataException


def request_params(serializer_class=None, need_user=False, unpack=True):
    """
    request_params 装饰器用于自动解析请求参数，并可选地进行验证和用户提取。
    它简化了视图函数中的参数处理，支持 GET 和 POST 请求类型。

    参数:
        serializer_class (serializers.Serializer, optional): 用于验证和解析请求参数的序列化器类。
            如果不提供，装饰器将仅解析参数而不进行验证。
        need_user (bool, optional): 是否需要将请求的用户对象作为参数传递给视图函数。
            如果为 True，则在调用视图函数时将 user 作为参数传递。
        unpack (bool, optional): 是否将表单参数进行解包,默认True
            如果为 False, serializer_class所指定的表单对象将作为参数传递
            否则, 将表单参数解包(**serializer_class.data)作为参数传递

    策略:
        1. 对于 GET 请求，解析查询参数（query_params）。
        2. 对于 POST 请求，解析请求体数据（data）。
        3. 如果提供了序列化器类，使用它来验证解析后的参数。
            - 如果验证失败，抛出 DataException 异常，并返回错误信息。
            - 如果验证通过，将验证后的数据作为命名参数传递给视图函数。
        4. 如果需要用户对象，将其作为参数传递给视图函数。

    返回:
        decorator (function): 装饰器函数。

    使用方法:
    1. 在需要自动解析和验证请求参数的视图函数上添加 @request_params() 装饰器。
    2. 如果需要参数验证，可以传递一个序列化器类作为 serializer_class 参数。
    3. 如果需要用户对象，将 need_user 设置为 True。

    示例:
    @request_params(MyParamsSerializer, need_user=True)
    def some_view_function(request, user, param1, param2):
        # 视图逻辑
        pass

    @request_params()
    def another_view_function(request, **params):
        # 无需验证的视图逻辑
        pass

    作者：魏文海，2024年8月10日
    """

    def decorator(func):
        @wraps(func)
        def wrapper(request, *args, **kwargs):
            _request = request.request

            # 解析请求参数
            if _request.method == 'GET':
                data = _request.query_params
            else:
                data = _request.data

            # 处理 QueryDict 对象，将字符串转换为合适的 Python 数据类型
            if isinstance(data, QueryDict):
                data = data.dict()

            for key, value in data.items():
                if isinstance(value, str):
                    if ',' in value:  # 处理逗号分隔的字符串
                        data[key] = [int(v) if v.isdigit() else v for v in value.split(',')]
                    elif value.isdigit():  # 纯数字字符串转换为整数
                        data[key] = int(value)

            # 验证请求参数
            if serializer_class:
                serializer = serializer_class(data=data)
                if not serializer.is_valid():
                    raise ValidationException(serializer.errors)
                validated_data = serializer.validated_data if unpack else {'forms': serializer}
            else:
                validated_data = data

            # 提取用户对象（如果需要）
            user = _request.user if need_user else None
            if need_user and (user is None or not user.is_authenticated):
                raise DataException('请登录后再进行操作')

            # 如果有签名，需要将签名剔除
            if validated_data.get('sign_value', None):
                validated_data.pop('sign_value')

            # 调用视图函数，传递解析后的参数和用户对象（如果需要）
            return func(request, user=user, **validated_data) if need_user else func(request, **validated_data)

        return wrapper

    return decorator
